<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>表单验证</title>
		<style>
			label{
				display: inline-block;
				width: 150px;
			}
		</style>
	</head>
	<body>
		<form action="" id="form">
			<label for="alone">非空</label><input type="text" name="isNull"><br/>
			<label for="alone">身份证号码</label><input type="text" name="idCard"><br/>
			<label for="alone">手机号(国内11位)</label><input type="text" name="phone"><br/>
			<label for="alone">邮箱</label><input type="text" name="email"><br/>
			<label for="alone">最大最小值</label><input type="text" name="maxmin"><br/>
			<button id="submit">提交</button>
		</form>
		<hr>
		<label for="alone">单项验证</label>
		<input type="text" name="alone">
		
		<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
		<script>
			/*
			 * jquery-validate.js
			 */
			if(window.jQuery === undefined){
				throw new Error('Please load jquery.js before loading jquery-validate.js')
			}
			
			(function (window, jQuery) {
				
				const regExpHandler = {
					text: function (rules) {
						return function (el, value, callback) {
							if(value === '' || value === undefined || value === null){
								return callback(new Error(rules.message || 'error: message'));
							}else{
								return callback()
							}
						}
					},
					idCard: function (rules) {
						return function (el, value, callback) {
							let reg = /^[1-9]\d{5}([1-9]\d{3})((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
							if(reg.test(value)){
								return callback();
							}else{
								return callback(new Error(rules.message || 'error: message'));
							}
						}
					},
					phone: function (rules) {
						return function (el, value, callback) {
							let reg = /^[1-9]\d{10}/
							if(reg.test(value)){
								return callback();
							}else{
								return callback(new Error(rules.message || 'error: message'));
							}
						}
					},
					email: function (rules) {
						return function (el, value, callback) {
							let reg = /\w+@\w+.\w+/
							if(reg.test(value)){
								return callback();
							}else{
								return callback(new Error(rules.message || 'error: message'));
							}
						}
					},
					maxmin: function (rules) {
						return function (el, value, callback) {
							value -= 0;
							console.log(value);
							if(rules.min <= value && value <= rules.max){
								return callback();
							}else{
								return callback(new Error(rules.message || 'error: message'));
							}
						}
					}
				}
				
				jQuery.extend({
					validate: function (el, option) {
						let len, i=0;
						if(jQuery.isArray(option)===false){
							return el;
						}
						len = option.length;
						
						errorElement = function (el) {
							el.style.borderColor = 'red'
						}
						successElement = function (el) {
							el.style.borderColor = 'green'
						}
						
						for(; i<len; i++){
							let rules = option[i];
							if(jQuery.isPlainObject(rules)){

								let handler = rules.validator || regExpHandler[rules.type || 'text'](rules);				
								
								jQuery.fn.on.call($(el), 'validate', function (e) {
									handler(el, el.value, function (error) {
										if(error){
											alert(error.message);
											errorElement(el)
											throw error;
										}else{
											successElement(el)
										}
									});
								})
								
								rules.defaultEvent && jQuery.fn.on.call($(el), rules.defaultEvent, function (e) {
									handler(el, el.value, function (error) {
										if(error){
											alert(error.message);
											errorElement(el);
										}else{
											successElement(el)
										}
									});
								})
							}
						}
					}
				})
				jQuery.fn.extend({
					validate: function(options){
						let elements = this, name;
						
						if(elements.is('form')){
							elements = elements.find('[name]');
						}
						
						if(jQuery.isPlainObject(options)){
							return elements.each(function (index, item) {
								name = item.getAttribute('name');
								options[name] && jQuery.validate(item, options[name]);
							})
						}
						if(jQuery.isArray(options)){
							return elements.each(function (index, item) {
								jQuery.validate(item, options);
							})
						}
						if(typeof options === 'function'){
							try{
								elements.trigger('validate');
								options(true)
							}catch(e){
								options(false)
							}
						}
					},
				})
				
			})(window, window.$)
			
			// 整个form表单验证
			// 除input之外,所有具有value的表单元素都可参与验证
			// 验证方法为 指定各个表单元素的name值,并配置自定义的验证方法
			// defaultEvent: 触发验证的事件
			// type: 默认的验证方法 5种 空/身份证/电话/Email/最大最小值
			// message: 验证失败后的message
			// validator: 用户自定义的验证方法,验证成功则return callback(),验证失败return callback(new Error('your error message'));
			// (validator和type同时存在时，会使用validator的验证方法)
			$('#form').validate({
				'isNull': [
					{
						defaultEvent: 'change',
						type: 'text',
						message: '不能为空',
					},
					{
						defaultEvent: 'change',
						validator: function(el, value, callback){
							if(value === '123'){
								return callback()
							}else{
								return callback(new Error('必须等于“123”'));
							}
						}
					},
				],
				'idCard': [
					{
						defaultEvent: 'change',
						type: 'idCard',
						message: '请输入正确的身份证号码',
					},
				],
				'phone': [
					{
						defaultEvent: 'change',
						type: 'phone',
						message: '请输入11位国内手机号码',
					},
				],
				'email': [
					{
						defaultEvent: 'change',
						type: 'email',
						message: '请输入正确的邮箱',
					},
				],
				'maxmin': [
					{
						defaultEvent: 'change',
						type: 'maxmin',
						max: 100,
						min: 0,
						message: '请输入100-0之间的数字',
					},
				]
			})
			$('#submit').click(function () {
				$('#form').validate(valid => {
					if(valid){
						console.log('表单验证成功')
					}else{
						console.log('表单验证失败')
					}
				})
				return false;
			})
			
			
			// 单项input验证
			$('input[name=alone]').validate([
				{
					defaultEvent: 'change',
					validator: function(el, value, callback){
						
						if(value != value-0){
							console.log(value);
							console.log(value-0);
							return callback(new Error('必须输入数字'));
						}
						
						value -= 0;
						
						if(value < 100 || value > 200){
							return callback()
						}else{
							return callback(new Error('输入值应小于100或者大于200'));
						}
					}
				}
			])
		</script>
	</body>
</html>
